package baseObjectContract;
import assertTools.DecoratorTools;
import baseObject.IBall;
import baseObject.IBrickBreaker;
import baseObjectDecorator.BallDecorator;

public class BallContract extends BallDecorator{
	private IBall ball;

	public BallContract(IBall ball){
		super(ball);
		this.ball = ball;
	}

	public void init(int x, int y, int width, int height){
		DecoratorTools.checkPre(x >= 0 && y >= 0 && width >= 0 && height >= 0);
		DecoratorTools.checkPre(x + width <= IBrickBreaker.XMAX && y + height <= IBrickBreaker.YMAX);

		ball.init(x, y, width, height);

		DecoratorTools.checkPost(super.getDeltaX() == 1 && super.getDeltaY() == 1);
		DecoratorTools.checkPost(super.getX() == x && super.getY() == y);

		this.checkInvariantBall();
	}

	private void checkInvariantBall(){
		DecoratorTools.checkInv(super.getDeltaX() == -1 || super.getDeltaX() == 1);
		DecoratorTools.checkInv(super.getDeltaY() == -1 || super.getDeltaY() == 1);
		DecoratorTools.checkInv(super.getSpeed() > 0);
	}

	public void setDirection(int deltaX,int deltaY){
		IBall ballAtOld = (IBall) this.ball.cloneObj();

		this.checkInvariantBall();

		DecoratorTools.checkPre(deltaX == -1 || deltaX == 0 || deltaX == 1);
		DecoratorTools.checkPre(deltaY == -1 || deltaY == 0 || deltaY == 1);

		super.setDirection(deltaX, deltaY);

		if(this.getDeltaX() != 0)
			DecoratorTools.checkPost(super.getDeltaX() == deltaX);
		else
			DecoratorTools.checkPost(super.getDeltaX() == ballAtOld.getDeltaX());

		if(this.getDeltaY() != 0)
			DecoratorTools.checkPost(super.getDeltaY() == deltaY);
		else
			DecoratorTools.checkPost(super.getDeltaY() == ballAtOld.getDeltaY());

		DecoratorTools.checkPost(super.getSpeed() == ballAtOld.getSpeed());
		DecoratorTools.checkPost(super.getX() == ballAtOld.getX());
		DecoratorTools.checkPost(super.getY() == ballAtOld.getY());

		this.checkInvariantBall();

	}

	public void setSpeed(int speed){
		IBall ballAtOld = (IBall) this.ball.cloneObj();

		this.checkInvariantBall();

		DecoratorTools.checkPre(speed > 0);

		super.setSpeed(speed);

		DecoratorTools.checkPost(super.getSpeed() == speed);
		DecoratorTools.checkPost(super.getDeltaX() == ballAtOld.getDeltaX());
		DecoratorTools.checkPost(super.getDeltaY() == ballAtOld.getDeltaY());
		DecoratorTools.checkPost(super.getX() == ballAtOld.getX());
		DecoratorTools.checkPost(super.getY() == ballAtOld.getY());

		this.checkInvariantBall();

	}

	public void invertDirection(boolean inX,boolean inY){
		IBall ballAtOld = (IBall) this.ball.cloneObj();

		this.checkInvariantBall();

		super.invertDirection(inX, inY);

		if(inX)
			DecoratorTools.checkPost(super.getDeltaX() == -ballAtOld.getDeltaX());
		if(inY)
			DecoratorTools.checkPost(super.getDeltaY() == -ballAtOld.getDeltaY());

		DecoratorTools.checkPost(super.getSpeed() == ballAtOld.getSpeed());
		DecoratorTools.checkPost(super.getX() == ballAtOld.getX());
		DecoratorTools.checkPost(super.getY() == ballAtOld.getY());

		this.checkInvariantBall();
	}

	public void move(){
		IBall ballAtOld = (IBall) this.ball.cloneObj();

		this.checkInvariantBall();

		super.move();

		DecoratorTools.checkPost(super.getX() == ballAtOld.getX() + 
				ballAtOld.getDeltaX() * ballAtOld.getSpeed());
		DecoratorTools.checkPost(super.getY() == ballAtOld.getY() +
				ballAtOld.getDeltaY() * ballAtOld.getSpeed());
		DecoratorTools.checkPost(super.getDeltaX() == ballAtOld.getDeltaX());
		DecoratorTools.checkPost(super.getDeltaY() == ballAtOld.getDeltaY());
		DecoratorTools.checkPost(super.getSpeed() == ballAtOld.getSpeed());
	}

	public int getDeltaX() {
		return super.getDeltaX();
	}

	public int getDeltaY() {
		return super.getDeltaY();
	}

	public int getSpeed() {
		return super.getSpeed();
	}
	
	public int getWidth() {
		return super.getWidth();
	}

	public int getHeight() {
		return super.getHeight();
	}

	@Override
	public Object cloneObj() {
		return this.ball.cloneObj();
	}
}
